#include "PoolAllocator.h"
#include "Atomic.h"
#include "Assertions.h"

namespace CEngine
{

PoolAllocator::PoolAllocator(U64 size, U64 number)
    :   freeElements(number),
        totalElements(number),
        elementSize(size)
{
    ASSERT(size >= 8);

    nextElementPointer = poolPointer = new U8[size * number];

    clear();
}

PoolAllocator::PoolAllocator(U64 size, U64 number, U64 alignment)
    :   freeElements(number),
        totalElements(number),
        elementSize(size)
{
    ASSERT(size >= 8);

    poolPointer = new U8[size * number];

    U64 mask = alignment - 1;
    U64 misalignment = ((U64)poolPointer & mask);
    U64 adjustment = alignment - misalignment;

    nextElementPointer = poolPointer + (alignment - adjustment);

    clear();
}

PoolAllocator::~PoolAllocator(void)
{
    delete[] (U8*)poolPointer;
    poolPointer = NULL;
    nextElementPointer = NULL;
    freeElements = 0;
    totalElements = 0;
}

void*
PoolAllocator::alloc(void) {
    if (freeElements == 0)
        return NULL;

    void* temp = nextElementPointer;
    U64 nextTemp = *(U64*)temp;

    nextElementPointer = (void*)nextTemp;

    freeElements--;

    return temp;
}

void
PoolAllocator::free(void* pointer) {
    if (pointer == NULL) {
        return;
    }
    *(U64*)pointer = (U64)nextElementPointer;
    nextElementPointer = pointer;
    freeElements++;
}

void
PoolAllocator::clear(void) {
    for (U64 i = 0; i < totalElements; i++) {
        void* nextTemp = poolPointer + ((i + 1) * elementSize);
        void* temp = poolPointer + (i * elementSize);
        *(U64*)temp = (U64)nextTemp;
    }
    void* temp = poolPointer + ((totalElements - 1) * elementSize);
    *(U64*)temp = (U64)NULL;
}

}
